/*
*  LLNotifier.cpp
*  zMatch
*
*  Created by Alexander Trutchenko on 17/11/11.
*  Copyright 2011 League of Independent Developers. All rights reserved.
*
*/

#include "lid_lib/src/data_managment/LLNotifier.h"

#include "lid_lib/src/data_managment/LLNotifierObserver.h"
#include "lid_lib/src/service/LLAssert.h"

namespace lidlib {

////////////////////////////////////////////////////////
//
/** LLNotifier
*/
////////////////////////////////////////////////////////

LLNotifier* LLNotifier::_instance = NULL;

void LLNotifier::registerObserver(LLNotifierObserver* observer, const std::string& notificationName)
{
    if (NULL == _instance) {
        _instance = new LLNotifier();
    }
    _instance->doRegisterObserver(observer, notificationName);
}

void LLNotifier::unregisterObserver(LLNotifierObserver* observer)
{
    if (_instance == NULL)
        return;
    _instance->doUnregisterObserver(observer);
}

void LLNotifier::sendNotification(const std::string& notificationName, const void* pData)
{
    if (_instance == NULL)
        return;
    _instance->doSendNotification(notificationName, pData);
}

void LLNotifier::doRegisterObserver(LLNotifierObserver* observer, const std::string& notificationName)
{
	LLAssert(!notificationName.empty(), "LLNotifier: Disable to register observer for empty notification string!");
	if (_blockerCounter > 0)
    {
        _listToRegisterUnregister.push_back(LLObserversListToRegisterUnregister::value_type(observer, notificationName));
        return;
    }
    LLObservers::iterator it = _observers.find(notificationName);
    if (it == _observers.end())
    {
        _observers[notificationName] = LLObserverList();
        it = _observers.find(notificationName);
    }
    LLObserverList::const_iterator itList = it->second.begin();
    for (; itList != it->second.end(); ++itList)
        if (*itList == observer)
            break;

    if (itList == it->second.end())
	{
        it->second.push_back(observer);
	}
}

void LLNotifier::doUnregisterObserver(LLNotifierObserver* observer)
{
//    if (_blocker)
	if (_blockerCounter > 0)
    {
        _listToRegisterUnregister.push_back(LLObserversListToRegisterUnregister::value_type(observer, ""));
        return;
    }
    LLObservers::iterator it = _observers.begin();
    while (it != _observers.end())
    {
        LLObservers::iterator itDel = it;
        ++it;
        LLObserverList::iterator itList = itDel->second.begin();
        for (; itList != itDel->second.end(); ++itList)
            if (*itList == observer)
            {
                itDel->second.erase(itList);
                break;
            }
            if (itDel->second.empty())
                _observers.erase(itDel->first);
    }
}

void LLNotifier::doSendNotification(const std::string& notificationName, const void* pData)
{
//   LLAssert(!_blocker, "LLNotifier: you must not send notification during notification process!");

	++_blockerCounter;
    LLObservers::const_iterator it = _observers.find(notificationName);
	if (it == _observers.end())
	{
		--_blockerCounter;
    	return;
	}

	LLObserverList::const_iterator itList = it->second.begin();
    for (; itList != it->second.end(); ++itList)
        (*itList)->onReceiveNotification(notificationName, pData);

	--_blockerCounter;
	if (_blockerCounter == 0)
	{
		for (LLObserversListToRegisterUnregister::const_iterator it = _listToRegisterUnregister.begin(); it != _listToRegisterUnregister.end(); ++it)
		{
			if (it->second.empty())
				doUnregisterObserver(it->first);
			else
				doRegisterObserver(it->first, it->second);
		}
		_listToRegisterUnregister.clear();
	}
}

} // namespace lidlib
